import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Random;


public class BadugiBot extends Thread {
	Socket socket = null;
	private Socket botSocket;
	private DataOutputStream writer;
	private DataInputStream reader;
	int botID = 0, botChips = 0, botChipsOnStart = 0, botBet = 0, botTotalBet = 0, botSuggestedMaxBet = 0;
	int numberOfPlayers = 0, gameCurrentRound = 1, gameMaxBet = 0, gamePot = 0;

	double botChance = 0;
	
	boolean isGameOpen = false, ifBotWins = false, botMovesEnabled = true;
	boolean[] botPossibleMoves;
	
	String botName = "BadugiBot", action = "";
	String[][] botCards;
	
	BadugiBot(String host, int port, String _botName) {
		botName = _botName;
		try {
			botSocket = new Socket(host, port);

			System.out.println("\n > Bot successfully connected to server :)\n");

			reader = new DataInputStream(botSocket.getInputStream());
			writer = new DataOutputStream(botSocket.getOutputStream());

			start();
			
		} catch (IOException e) {
			System.out.println("\n > Cannot connect to '" + host + "' (port: " + port + ")\n");
			System.exit(-1);
		}
	}
	
	private void sendRequest(String message) {
		try {
			writer.writeUTF(message);
		} catch (Exception e) {
			System.out.println(e);
		}
	}	
	
	public void run() {
		try {
			while (true) {
				String response = reader.readUTF();
					if (response == null)
					continue;
					
				String[] tab = response.split(" ");
				String cmd = tab[0];

				if (cmd.equalsIgnoreCase("numberOfPlayers")) {
					numberOfPlayers = Integer.parseInt(tab[1]);
					
				} else if (cmd.equalsIgnoreCase("yourID")) {
					botID = Integer.parseInt(tab[1]);
					
				} else if (cmd.equalsIgnoreCase("yourName")) {
					botName = tab[1];

				} else if (cmd.equalsIgnoreCase("yourCards")) {
					botCards = new String[4][3];
					
					for (int i = 1; i <= 4; i++) {
						String[] card = tab[i].split("-");
						botCards[i-1] = new String[]{
								i + "",
								card[0],
								card[1] + "-" + card[2] };
					}
					
					sortCards();
					
				} else if (cmd.equalsIgnoreCase("yourChips")) {
					botChips = Integer.parseInt(tab[1]);
					
					if (!isGameOpen) {
						botChipsOnStart = botChips;
						calculateChanceAndMaxBet();
					}
					
				} else if (cmd.equalsIgnoreCase("chipsWithAward")) {
					botChips = Integer.parseInt(tab[1]);
					System.out.println("   My chips with award: " + botChips);
					
				} else if (cmd.equalsIgnoreCase("yourChipsOnRoundStart")) {
					botChips = Integer.parseInt(tab[1]);
					calculateChanceAndMaxBet();
					
				} else if (cmd.equalsIgnoreCase("actionOk")) {
					
					if (action.equalsIgnoreCase("fold")) {
						botMovesEnabled = false;
						
					} else {
						sendRequest("returnMyChips");
					}
					
					action = "";
					
				} else if (cmd.equalsIgnoreCase("actionError")) {
					botActionError(action);
					
				} else if (cmd.equalsIgnoreCase("startOfTheGame")) {
					isGameOpen = true;

				} else if (cmd.equalsIgnoreCase("startData")) {
					calculateChanceAndMaxBet();
					System.out.println("   My hand strength: " + botChance + "%");
					
					if (tab[2].equalsIgnoreCase(botID + "")) {
						botPossibleMoves(tab);
						itsBotMove();
					}
						
					if (tab[8].equals(botID + ""))
						botBet = Integer.parseInt(tab[7]);
					else if (tab[10].equals(botID + ""))
						botBet = Integer.parseInt(tab[9]);
					
					
				} else if (cmd.equalsIgnoreCase("nextPlayerMove")) {
					if ((tab[1].equalsIgnoreCase(botID + "")) && (botMovesEnabled)) {
						botPossibleMoves(tab);
						itsBotMove();
					}
					
				} else if (cmd.equalsIgnoreCase("endOfRound")) {
					
					
					
				} else if (cmd.equalsIgnoreCase("newRound")) {
					gameCurrentRound = Integer.parseInt(tab[1]);
					gameMaxBet = 0;
					botBet = 0;
					
					if (gameCurrentRound % 2 == 0) {
						drawCards();
					} else {
						calculateChanceAndMaxBet();
						
						System.out.println("   My cards:");
						
						for (int i = 0; i <= 3; i++) {
							System.out.println(" * " + botCards[i][1] + "-" + botCards[i][2] + " ");
						}
						
						System.out.println("\n   My hand strength: " + botChance + "%");
						System.out.println("   I have $" + botSuggestedMaxBet + " to spend");
					}
					
				} else if (cmd.equalsIgnoreCase("disableMoves")) {
					botMovesEnabled = false;
					break;
					
				} else if (cmd.equalsIgnoreCase("endOfGame")) {
					isGameOpen = false;
					
				} else if (cmd.equalsIgnoreCase("gameResult")) {
					
					if (tab[1].equalsIgnoreCase("winner")) {
						if (tab[2].equals(botID + "")) {
							sendRequest("returnMyAward");
							ifBotWins = true;
							System.out.println("\n > Yeah, I won! :)\n");
						} else {
							ifBotWins = false;
						}
							
					} else {
						ifBotWins = false;
					}
					
					sendRequest("returnMyCards");
					sendRequest("returnMyChips");
					sendRequest("nextGameYes");

				} else if (cmd.equalsIgnoreCase("tableUpdate")) {

					if (tab[1].equals("potAndMaxBet")) {
						gamePot = Integer.parseInt(tab[2]);
						gameMaxBet = Integer.parseInt(tab[3]);
						
					} else if (tab[1].equals("yourBet")) {
						botTotalBet = Integer.parseInt(tab[2]);
						botChips = botChipsOnStart - botTotalBet;
					}
				} else if (cmd.equalsIgnoreCase("welcomeInGame")) {
					System.out.println("Welcome");
					sendRequest("numberOfPlayers");
					sendRequest("returnMyID");
					sendRequest("setPlayerName " + botName);
					sendRequest("returnMyCards");
					sendRequest("returnMyChips");
				} 
			} 
		} catch (Exception e) { 
			System.out.println("Player - Exception");
		}
	}
	
	private void botPossibleMoves(String[] tab) {
		boolean check = false, bet = false, call = false, raise = false, allIn = false;
		boolean[] possibleActions = new boolean[]{check, bet, call, raise, allIn};
		int index = 0;
		
		for (int i = tab.length-5; i < tab.length; i++) {
			possibleActions[index] = Boolean.parseBoolean(tab[i]);
			
			index += 1;
		}
		
		botPossibleMoves = possibleActions;
	}
	
	private void itsBotMove() {
		calculateChanceAndMaxBet();
		boolean[] m = botPossibleMoves;
		int amount = 0;
		
		Random rand = new Random();
		
		try {
			amount = rand.nextInt((int)(Math.round((botSuggestedMaxBet - botBet)*(botChance/100) + 0.5d))) + 1;
		} catch (Exception e) {
			amount = 1;
		}
		

		
		if (botChance < 4) {
			if (gameCurrentRound == 1)
				action = "fold";
			else
				action = "allIn";
			
		} else if (botChance < 10) {
			if (m[0])
				action = "check";
			else if (m[2] && gameMaxBet <= botChips*0.1)
				action = "call";
			else
				action = "allIn";
			
		} else if (botChance >= 10 && botChance < 20) {
			amount = (int)(Math.round(amount/4 + 0.5d));
			
			if (amount < 1)
				amount = 1;
			
			if (m[1])
				action = "bet 1";
			else if (m[2] && gameMaxBet <= botSuggestedMaxBet)
				action = "call";
			else
				action = "allIn";
			
		} else if (botChance >= 20 && botChance <= 35) {
			amount = (int)(Math.round(amount/2 + 0.5d));

			
			if (m[1])
				action = "bet " + amount;
			else if (m[3] && gameMaxBet + amount <= botSuggestedMaxBet)
				action = "raise " + amount;
			else if (m[3] && gameMaxBet + 1 <= botSuggestedMaxBet)
				action = "raise 1";
			else 
				action = "call";
			
		} else {
			int amount_half = (int)(Math.round(amount/2 + 0.5d));
			
			if (m[1])
				action = "bet " + amount;
			else if (m[3] && gameMaxBet + amount <= botSuggestedMaxBet)
				action = "raise " + amount;
			else if (m[3] && gameMaxBet + amount_half <= botSuggestedMaxBet)
				action = "raise " + amount_half;
			else if (m[3] && gameMaxBet + 1 <= botSuggestedMaxBet)
				action = "raise 1";
			else
				action = "call";
		}
		
		System.out.println(" > My next move is: " + action);
		
		
		try {
			sleep(1500);
			sendRequest(action);
		} catch (Exception e) {
			sendRequest(action);
		}
	}
	
	
	
	private void drawCards() {
		String cardsToChange = "";
		
		/* Jesli najsilniejsza (najmniejsza) karta jest wieksza od 6,
		 * to wymieniamy ja.
		 */
		if (Integer.parseInt(botCards[0][1]) > 6) {
			System.out.println(" > Drawing card: " + botCards[0][1] + "-" + botCards[0][2]);
			cardsToChange += " 1";
		}

		/*
		 * Porownujemy kazda karte z kazda. Jesli porownywana karta ma taka sama
		 * wartosc lub kolor jak wzorzec, ta wymieniamy ta wyzsza, ktora i tak jest usuwana
		 * przy koncowym porownywaniu kart wszystkich uzytkownikow.
		 */
		for (int i = 0; i < 3; i++) {
			for (int j = i+1; j < 4; j++) {
				if (botCards[i][1].equalsIgnoreCase(botCards[j][1]) || botCards[i][2].equalsIgnoreCase(botCards[j][2])) {
					if (!cardsToChange.contains(botCards[j][0])) {
						cardsToChange += " " + botCards[j][0];
						System.out.println(" > Drawing card: " + botCards[j][1] + "-" + botCards[j][2]);
					}
				}
			}
		}
		
		try {
			sleep(1000 + botID * 100);
		} catch (Exception e) {}

		if (cardsToChange != "")
			sendRequest("drawMyCards" + cardsToChange);
		else
			sendRequest("dontDrawMyCards");
	}
	
	private void calculateChanceAndMaxBet() {
		botChance = botChance();
	
		if (botChance > 90) {
			botSuggestedMaxBet = botChips;
		} else {
			botSuggestedMaxBet = (int)(Math.round(botChips*botChance/100 + 0.5d));
		}
	}
	
	
	private void botActionError(String act) {
		String[] actTab = act.split(" ");
		String actCmd = actTab[0];
		
		if (act.equals("allIn"))
			action = "fold";
		else if (act.equals("call"))
			action = "allIn";
		else if (act.equals("bet 1"))
			action = "check";
		else if (actCmd.equals("bet"))
			action = "bet 1";
		else if (act.equals("raise 1"))
			action = "call";
		else if (actCmd.equals("raise"))
			action = "raise 1";
		
		try {
			sleep(1000);
		} catch (Exception e) {}
		
		sendRequest(action);
	}
	
	double botChance() {
		int prev = 0, index = 0;
		double chance = 0;
		String colors = "";
		int[] cardsValues = new int[4];
		String[][] tmpBotCards = botCards;
		
		for (int i = 0; i <= 3; i++) {
			if (prev != Integer.parseInt(tmpBotCards[i][1]) && !colors.contains(tmpBotCards[i][2])) {
				prev = Integer.parseInt(tmpBotCards[i][1]);
				colors += tmpBotCards[i][2];
				cardsValues[index] = prev;
				index += 1;
			}
		}
		
		int[] best = new int[]{1,2,3,4};
		int[] worst = new int[]{13,14,14,14};
		int nullValues = 1;
		
		for (int i = 0; i <= 3; i++) {
			if (cardsValues[i] == 0) {
				cardsValues[i] = 14;
				nullValues += 1;
			}
			

			chance += ((worst[i] - cardsValues[i])*100) / (worst[i] - best[i]);
		}
		
		chance = Math.round(chance/(4*nullValues) + 0.5d);
		botChance = chance;
		return chance;
	}

	
	void sortCards() {
		String[][] sorted = new String[4][3];
		int j = 0, minIndex = 0;

		for (int i = 0; i < botCards.length; i++) {
			int min = 15;
			
			for (j = 0; j < botCards.length; j++) {
				if (botCards[j][0] != null) {
					if (Integer.parseInt(botCards[j][1]) < min) {
						min = Integer.parseInt(botCards[j][1]);
						minIndex = j;
					}
				}
			}
			
			sorted[i] = botCards[minIndex];
			botCards[minIndex] = new String[3];
		}
		
		botCards = sorted;	
	}
	
	public static void main(String[] args) {
		String playerName = "Bot", host;
		int port;

		try {
			host = args[0];
			port = Integer.parseInt(args[1]);
		} catch (Exception e) {
			port = 4444;
			host = "localhost";
		}

		new BadugiBot(host, port, playerName);
	}
}
